package com.kpmg.datalake.reportanalysis.controller;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.kpmg.datalake.common.enums.ResultCodeEnum;
import com.kpmg.datalake.common.exception.BusinessException;
import com.kpmg.datalake.common.exception.CustomException;
import com.kpmg.datalake.common.model.DataExportCondition;
import com.kpmg.datalake.common.privilege.ValidateDataAuth;
import com.kpmg.datalake.common.utils.AssertUtil;
import com.kpmg.datalake.common.utils.ContextHolderUtils;
import com.kpmg.datalake.common.utils.ExceptionUtil;
import com.kpmg.datalake.common.utils.ResponseUtils;
import com.kpmg.datalake.common.vo.KeyAndValueDTO;
import com.kpmg.datalake.common.vo.ServerResponse;
import com.kpmg.datalake.db.model.RqsList;
import com.kpmg.datalake.db.model.SysUsr;
import com.kpmg.datalake.operatelog.annotation.OptLog;
import com.kpmg.datalake.operatelog.enums.LogTypeEnum;
import com.kpmg.datalake.reportanalysis.service.DataService;
import com.kpmg.datalake.reportanalysis.vo.QueryAndExportVO;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.Duration;
import java.time.Instant;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * 数据相关操作控制器
 * @author Tony
 */
@RestController
@RequestMapping("/queryAndExport")
public class DataController {
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(DataController.class);
    /**
     * 注入服务
     */
    @Resource
    private DataService dataService;

    /**
     * 查询请求列表
     */
    @PostMapping("/requestList")
    @OptLog(logType = LogTypeEnum.OPERATION, module = "reportAnalysis", description = "查询科目余额表与序时账")
    @ValidateDataAuth(key = "#queryObj.getProjectId()")
    public ServerResponse<PageInfo> showRqsList2(@RequestBody QueryAndExportVO queryObj) {
        return dataService.getRequestList2(queryObj.getProjectId(), queryObj.getQueryParam(), queryObj.getOrderColumn(), queryObj.getOrderBy(), queryObj.getPageNum(), queryObj.getPageSize());
    }

    /**
     * 获取会计年月
     */
    @GetMapping("/getAccYearMonth")
    public ServerResponse<JSONObject> getAccYearMonth(@RequestParam("projectId") String projectId) {
        JSONObject result;
        try {
            result = dataService.getAccYearMonth(projectId);
            return ServerResponse.createBySuccess(result);
        } catch (Exception e) {
            logger.error("获取会计年月异常:{}", e.getMessage(), e);
            return ServerResponse.createByErrorMessage("获取会计年月失败");
        }
    }

    /**
     * 导出所有账套信息
     */
    @PostMapping("/exportAllBookSet")
    public void exportAllBookSet(@RequestBody QueryAndExportVO queryObj, HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            // 获取用户信息
            SysUsr user = ContextHolderUtils.getLoginUser();
            // 导出所有账套信息
            AssertUtil.assertNotEmpty(queryObj.getProjectId(), "请选择账套");
            dataService.exportAllBookSet(queryObj.getProjectId(), user, request, response);
        } catch (Exception e) {
            logger.error("导出账套时异常:{}", e.getMessage(), e);
          try (OutputStream outputStream = response.getOutputStream()) {
            String outString = JSONObject.toJSONString(ServerResponse.createByErrorCodeMessage(
                ResultCodeEnum.CODE4041.getCode(), e.getLocalizedMessage()));
            outputStream.write(outString.getBytes());
          }
        }
    }

    /**
     * 上传筛选账套
     */
    @PostMapping("/uploadBookSet")
    public ServerResponse<String> uploadBookSet(MultipartFile selectedTemplate, HttpServletRequest request) {
        KeyAndValueDTO<Boolean, String> result;
        try {
            // 获取用户信息
            SysUsr user = ContextHolderUtils.getLoginUser();
            // 上传筛选账套
            result = dataService.uploadBookSet(user, selectedTemplate);
            if (result.getKey()) {
                // 设置账套文件路径
                request.getSession().setAttribute("bookLocation", result.getValue());
            }
            else{
                return ServerResponse.createByErrorMessage(result.getValue());
            }
        } catch (Exception e) {
            return ExceptionUtil.getExceptionMsg(e);
        }
        return ServerResponse.createBySuccessMessage(result.getValue());
    }

    /**
     * 数据导出请求
     */
    @PostMapping("/exportData")
    public ServerResponse<String> exportData(@RequestBody DataExportCondition condition, HttpSession session) {
        try {
            Instant start = Instant.now();
            // 获取用户信息
            SysUsr user = ContextHolderUtils.getLoginUser();
            // 获取用户账套路径信息
            String bookLocation = (String) session.getAttribute("bookLocation");
            bookLocation = StringUtils.isEmpty(bookLocation) ? condition.getBookLocation() : bookLocation;
            if (StringUtils.isEmpty(bookLocation)) {
                throw new CustomException("请上传筛选账套");
            }
            // 设置账套查询对象
            condition.setMonthList(dataService.getAccMonth(condition.getProjectId(), condition.getMonthBegin(), condition.getMonthEnd()));
            // 数据导出请求
            String requestNo = dataService.exportRequest(user, condition, bookLocation, condition.getProjectId());
            if(requestNo.startsWith("null+")){
                return ServerResponse.serverResponse(ResultCodeEnum.CODE4043, new Object[]{requestNo.split("\\+")[1]}, null);
            }
            Instant end = Instant.now();
            logger.info("数据导出请求:{}已生成，耗时：{}ms", requestNo, Duration.between(start, end).toMillis());
        } catch (Exception e) {
            logger.error("数据导出请求异常:{}" , e.getMessage(), e);
            return ServerResponse.createByErrorMessage("数据导出请求异常");
        }
        return ServerResponse.createBySuccessMessage("数据查询请求成功");
    }

    /**
     * 下载查询请求结果文件
     */
    @GetMapping("/resultDownload")
    @OptLog(logType = LogTypeEnum.OPERATION, module = "reportAnalysis", description = "下载")
    public void requestResultDownload(@RequestParam(value = "requestNo") String requestNo, HttpServletRequest request,
                                      HttpServletResponse response) throws IOException {
        // 获取用户信息
        SysUsr user = ContextHolderUtils.getLoginUser();
        // 日志记录下载
        dataService.logFileDownload(user.getUsrId(), requestNo);
        // 下载文件
        RqsList rqsList = dataService.selectRqsListById(requestNo);
        if (rqsList == null) {
            throw new BusinessException(ResultCodeEnum.CODE4041, "未找到对应的文件信息");
        }
        String filePath = rqsList.getFilePath();
        String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
        ResponseUtils.setZipDownloadResponseHeader(fileName, request, response);
        try (FileInputStream inputStream = new FileInputStream(filePath)) {
            IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            logger.error("下载查询请求结果文件异常:{}", e.getMessage(), e);
          try (OutputStream outputStream = response.getOutputStream()) {
            String outString = JSONObject.toJSONString(ServerResponse.createByErrorCodeMessage(
                ResultCodeEnum.CODE4041.getCode(), e.getLocalizedMessage()));
            outputStream.write(outString.getBytes());
          }
        }
    }

    @GetMapping("/exportCheckReport")
    @OptLog(logType = LogTypeEnum.OPERATION, module = "reportAnalysis", description = "校验报告")
    public void exportReport(@RequestParam(value = "projectId") String projectId, @RequestParam(value = "requestNo") String requestCode, HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            dataService.exportCheckReport(projectId, requestCode, request, response);
            logger.info("{}成功！", "导出报表信息");
        } catch (Exception e) {
            response.getWriter().write(JSONObject.toJSONString(ServerResponse.createByErrorCodeMessage(ResultCodeEnum.CODE4014.getCode(), "导出失败，请与系统管理员联系")));
            logger.error("下载校验报告{}", e.getMessage(), e);
        }
    }

}